#ifndef __OPERATION_H
#define __OPERATION_H

#include <vector>
#include <string>
#include <cassert>
#include <unordered_map>
#include "opencl_helper.h"
#include "utils.h"

namespace mslite{

enum MemType {
    Buffer = 1,
    Image2d = 2
};

class Operation {
public:
    Operation() = default;
    Operation(cl_context context);
    virtual ~Operation();
    virtual cl_int setInput(const std::vector<std::vector<float>>& inputs, cl_command_queue commandQueue);
    virtual std::vector<std::vector<int>> getInputShapes(void);
    virtual cl_int run(cl_command_queue commandQueue, cl_event &profEvent);
    inline std::string getKernelName(void) {return clKernelName;}
    virtual cl_int prepareMem(void) = 0;
    virtual cl_int getOutut(cl_command_queue commandQueue, std::vector<std::vector<float>> &output);
    virtual cl_int setParams(void) = 0;
    virtual cl_int setParams(std::vector<size_t> local);
    virtual cl_int bind(void) = 0;
protected:
    std::string clFileName;
    std::string clKernelName;
    std::string clCode;
    cl_context context;
    cl_program program;
    cl_kernel kernel;
    std::vector<size_t> globalThreads;
    std::vector<size_t> localThreads;
    std::unordered_map<std::string, cl_mem> memObjs;
    std::unordered_map<std::string, MemType> memTypes;
    std::vector<std::string> inputNames;
    std::vector<std::vector<int>> inputShapes;      // NHWC
    std::vector<std::vector<float>> inputs;
    std::vector<std::string> outputNames;
    std::vector<std::vector<int>> outputShapes;     // NHWC
    std::vector<std::vector<float>> outputs;
};

}

#endif